import base64
import json
import os
import pickle

from django.contrib.auth.mixins import LoginRequiredMixin
from django.http import HttpResponse
from django.shortcuts import render
from django.views import View
from django import http
import re
from django.db import DatabaseError
from django.contrib.auth import login
from django_redis import get_redis_connection
from django.core.paginator import Paginator, EmptyPage

from apps.areas.models import Area, Address
from apps.goods.models import SKU
from apps.orders.models import OrderInfo
from apps.shoppingcart.utils import merge_cart_cookie_to_redis
from apps.users.models import User
from django.shortcuts import redirect
from django.urls import reverse

from utils import constants
from utils.response_code import RETCODE
from django.contrib.auth import authenticate
from django.contrib.auth import logout

from utils.views import LoginRequiredJSONMixin
from suguo_mall.settings import BASE_DIR


class RegisterView(View):
    """用户注册"""

    def get(self, request):
        """
        提供注册界面
        :param request: 请求对象
        :return: 注册界面
        """
        return render(request, 'register.html')

    def post(self, request):
        # 1. 获取浏览器提交的数据
        username = request.POST.get('username')
        password = request.POST.get('password')
        password2 = request.POST.get('password2')
        mobile = request.POST.get('mobile')
        allow = request.POST.get('allow')
        sms_code = request.POST.get('sms_code')

        # 判断参数是否齐全
        if not all([username, password, password2, mobile, allow]):
            return http.HttpResponseBadRequest('缺少必传参数')
        # 判断用户名是否是5-20个字符
        if not re.match(r'^[a-zA-Z0-9_]{5,20}$', username):
            return http.HttpResponseBadRequest('请输入5-20个字符的用户名')
        # 判断密码是否是8-20个数字
        if not re.match(r'^[0-9A-Za-z]{8,20}$', password):
            return http.HttpResponseBadRequest('请输入8-20位的密码')
        # 判断两次密码是否一致
        if password != password2:
            return http.HttpResponseBadRequest('两次输入的密码不一致')
        # 判断手机号是否合法
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return http.HttpResponseBadRequest('请输入正确的手机号码')
        # 判断是否勾选用户协议
        if allow != 'on':
            return http.HttpResponseBadRequest('请勾选用户协议')

        redis_conn = get_redis_connection('code')
        sms_code_saved = redis_conn.get('sms_%s' % mobile)
        if sms_code_saved is None:
            return render(request, 'register.html', {'sms_code_errmsg': '无效的短信验证码'})
        if sms_code != sms_code_saved.decode():
            return render(request, 'register.html', {'sms_code_errmsg': '输入短信验证码有误'})

        # 保存注册数据
        try:
            user = User.objects.create_user(username=username, password=password, mobile=mobile)
        except DatabaseError:
            return render(request, 'register.html', {'register_errmsg': '注册失败'})

        # 实现状态保持
        login(request, user)
        # 响应注册结果
        # return http.HttpResponse('注册成功，重定向到首页')
        # return redirect(reverse('index:index'))
        response = redirect(reverse('index:index'))

        # 注册时用户名写到cookie，有效期15天
        response.set_cookie('username', user.username, max_age=3600 * 24 * 15)

        # 合并购物车
        response = merge_cart_cookie_to_redis(request=request, user=user, response=response)

        return response


class UsernameCountView(View):
    """判断用户名是否重复注册"""

    def get(self, request, username):
        """
        :param request: 请求对象
        :param username: 用户名
        :return: JSON
        """
        count = User.objects.filter(username=username).count()
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK', 'count': count})


class MobileCountView(View):
    """判断手机号是否重复注册"""

    def get(self, request, mobile):
        """
        :param request: 请求对象
        :param mobile: 手机号
        :return: JSON
        """
        count = User.objects.filter(mobile=mobile).count()
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK', 'count': count})


class LoginView(View):
    """用户名登录"""

    def get(self, request):
        """
        提供登录界面
        :param request: 请求对象
        :return: 登录界面
        """
        return render(request, 'login.html')

    def post(self, request):
        """
        实现登录逻辑
        :param request: 请求对象
        :return: 登录结果
        """
        # 接收参数
        username = request.POST.get('username')
        password = request.POST.get('password')
        remembered = request.POST.get('remembered')

        # 校验参数
        # 判断参数是否齐全
        if not all([username, password]):
            return http.HttpResponseBadRequest('缺少必传参数')

        # 判断用户名是否是5-20个字符
        if not re.match(r'^[a-zA-Z0-9_-]{5,20}$', username):
            # return http.HttpResponseBadRequest('请输入正确的用户名或手机号')
            return render(request, 'login.html', {'account_errmsg': '请输入正确的用户名或手机号'})

        # 判断密码是否是8-20个数字
        if not re.match(r'^[0-9A-Za-z]{8,20}$', password):
            # return http.HttpResponseBadRequest('密码最少8位，最长20位')
            return render(request, 'login.html', {'account_errmsg': '密码最少8位，最长20位'})

        # 认证登录用户
        user = authenticate(username=username, password=password)
        if user is None:
            return render(request, 'login.html', {'account_errmsg': '用户名或密码错误'})

        # 实现状态保持
        login(request, user)
        # 设置状态保持的周期
        if remembered != 'on':
            # 没有记住用户：浏览器会话结束就过期
            request.session.set_expiry(0)
        else:
            # 记住用户：None表示两周后过期
            request.session.set_expiry(None)

        # 响应登录结果
        next = request.GET.get('next')
        if next:
            response = redirect(next)
        else:
            response = redirect(reverse('index:index'))

        # 注册时用户名写入到cookie，有效期15天
        response.set_cookie('username', user.username, max_age=3600 * 24 * 15)

        return response


class LogoutView(View):
    """退出登录"""

    def get(self, request):
        """实现退出登录逻辑"""
        # 清理session
        logout(request)

        # 退出登录，重定向到登录页
        response = redirect(reverse('index:index'))

        # 退出登录时清除cookie中的username
        response.delete_cookie('username')

        return response


class UserCenterView(LoginRequiredMixin, View):
    """用户中心"""

    def get(self, request):
        """提供用户中心页面"""
        last_login = request.user.last_login
        print("最近访问时间是：%s" % last_login)
        last_login = str(last_login)
        last_login = last_login.split(".")[0]
        print(last_login)
        date_joined = request.user.date_joined
        print("创建时间是：%s" % last_login)
        date_joined = str(date_joined)
        date_joined = date_joined.split(".")[0]
        print(date_joined)

        # 判断用户是否登录
        user = request.user
        print(user)
        if user.is_authenticated:
            # 用户已登录，查询Redis购物车
            redis_conn = get_redis_connection('carts')
            redis_cart = redis_conn.hgetall('carts_%s' % user.id)
            cart_selected = redis_conn.smembers('selected_%s' % user.id)
            # 将redis中的两个数据统一格式，跟cookie中的格式一致，方便统一查询
            cart_dict = {}
            for sku_id, count in redis_cart.items():
                cart_dict[int(sku_id)] = {
                    'count': int(count),
                    'selected': sku_id in cart_selected
                }
        else:
            # 用户未登录，查询cookie购物车
            cart_str = request.COOKIES.get('carts')
            if cart_str:
                cart_dict = pickle.loads(base64.b64decode(cart_str.encode()))
            else:
                cart_dict = {}

        # 构造简单购物车JSON数据
        cart_skus = []
        sku_ids = cart_dict.keys()
        skus = SKU.objects.filter(id__in=sku_ids)
        for sku in skus:
            cart_skus.append({
                'id': sku.id,
                'name': sku.name,
                'price': sku.price,
                'count': cart_dict.get(sku.id).get('count'),
                'default_image_url': sku.default_image
            })
        print(cart_skus)
        # print(len(cart_skus))
        num = 0
        num2 = 0
        num3 = list()
        for c in cart_skus:
            # print(c["count"])
            # print(c['price'])
            num1 = c['count']
            price = c['price']*num1
            num += num1
            num3.append(num1)
            num2 += price
        # print(num)
        # print(num2)
        print(num3)
        context = {
            'username': request.user.username,
            'zheng_username': request.user.zheng_username,
            'sex': request.user.gender,
            'mobile': request.user.mobile,
            'email': request.user.email,
            'qq': request.user.qq_user,
            'tel': request.user.tel,
            'last_login': last_login,
            'date_joined': date_joined,
            'image': request.user.image,
            'cart_skus': cart_skus,
            'count': num,
            'price_mall': num2,
            'num3': num3,

        }
        return render(request, 'user_center.html', context=context)

    def post(self, request):
        print("调用post方法")
        json_dict = json.loads(request.body.decode())
        username = json_dict.get("username")
        zheng_username = json_dict.get("zheng_username")
        sex = json_dict.get("sex")
        email = json_dict.get("email")
        qq = json_dict.get("qq")
        mobil = json_dict.get("mobil")
        tel = json_dict.get("tel")


        # print(username, zheng_username, sex, email, qq, mobil, tel)
        request.user.username = username
        request.user.zheng_username = zheng_username
        request.user.sex = sex
        request.user.email = email
        request.user.qq_user = qq
        request.user.mobile = mobil
        request.user.tel = tel
        request.user.save()
        print("-------------成功-----------------------")
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': '添加成功'})


class Test(View):
    """上传头像"""

    def get(self, request):
        return render(request, 'test.html')

    def post(self, request):
        obj = request.POST.get('file')
        if request.method == 'POST':  # 获取对象
            obj = request.FILES.get('fafafa')
            # 上传文件的文件名

        print(obj.name)
        f = open(os.path.join(BASE_DIR, 'static', 'img', obj.name), 'wb')

        for chunk in obj.chunks():
            f.write(chunk)
            f.close()

            image = '/'.join((f.name).split('\\')[6:])
            print(image)
            request.user.image = "/" + image
            request.user.save()
            print("-------------成功-----------------------")

        return redirect(reverse('users:usercenter'))


class ChangePasswordView(LoginRequiredMixin, View):
    """修改密码"""

    def get(self, request):
        """展示修改密码界面"""
        return render(request, 'user_center_pass.html')

    def post(self, request):
        """实现修改密码逻辑"""
        # 1.接收参数
        old_password = request.POST.get('old_password')
        new_password = request.POST.get('new_password')
        new_password2 = request.POST.get('new_password2')
        # 2.验证参数
        if not all([old_password, new_password, new_password2]):
            return http.HttpResponseForbidden('缺少必传参数')
        if not re.match(r'^[0-9A-Za-z]{8,20}$', new_password):
            return http.HttpResponseBadRequest('密码最少8位，最长20位')
        if new_password != new_password2:
            return http.HttpResponseBadRequest('两次输入的密码不一致')

        # 3.检验旧密码是否正确
        if not request.user.check_password(old_password):
            return render(request, 'user_center_pass.html', {'origin_password_errmsg': '原始密码错误'})
        # 4.更新新密码
        try:
            request.user.set_password(new_password)
            request.user.save()
        except Exception as e:
            return render(request, 'user_center_pass.html', {'change_password_errmsg': '修改密码失败'})
        # 5.退出登陆,删除登陆信息
        logout(request)
        # 6.跳转到登陆页面
        response = redirect(reverse('users:login'))

        response.delete_cookie('username')

        return response


class AddressView(LoginRequiredMixin, View):
    """用户收货地址"""

    def get(self, request):
        """提供收货地址界面"""
        last_login = request.user.last_login
        print("最近访问时间是：%s" % last_login)
        last_login = str(last_login)
        last_login = last_login.split(".")[0]
        print(last_login)
        date_joined = request.user.date_joined
        print("创建时间是：%s" % last_login)
        date_joined = str(date_joined)
        date_joined = date_joined.split(".")[0]
        print(date_joined)
        addr = Address.objects.filter(user=request.user, is_deleted=0)
        # print(addr)
        # for area in addr:
        #     print(area.user.username)
        #     print(area.province)
        #     print(area.city)
        #     print(area.district)
        # 判断用户是否登录
        user = request.user
        print(user)
        if user.is_authenticated:
            # 用户已登录，查询Redis购物车
            redis_conn = get_redis_connection('carts')
            redis_cart = redis_conn.hgetall('carts_%s' % user.id)
            cart_selected = redis_conn.smembers('selected_%s' % user.id)
            # 将redis中的两个数据统一格式，跟cookie中的格式一致，方便统一查询
            cart_dict = {}
            for sku_id, count in redis_cart.items():
                cart_dict[int(sku_id)] = {
                    'count': int(count),
                    'selected': sku_id in cart_selected
                }
        else:
            # 用户未登录，查询cookie购物车
            cart_str = request.COOKIES.get('carts')
            if cart_str:
                cart_dict = pickle.loads(base64.b64decode(cart_str.encode()))
            else:
                cart_dict = {}

        # 构造简单购物车JSON数据
        cart_skus = []
        sku_ids = cart_dict.keys()
        skus = SKU.objects.filter(id__in=sku_ids)
        for sku in skus:
            cart_skus.append({
                'id': sku.id,
                'name': sku.name,
                'price': sku.price,
                'count': cart_dict.get(sku.id).get('count'),
                'default_image_url': sku.default_image
            })
        print(cart_skus)
        # print(len(cart_skus))
        num = 0
        num2 = 0
        num3 = list()
        for c in cart_skus:
            # print(c["count"])
            # print(c['price'])
            num1 = c['count']
            price = c['price'] * num1
            num += num1
            num3.append(num1)
            num2 += price
        # print(num)
        # print(num2)
        print(num3)
        context = {
            'addr': addr,
            'count1': len(addr),
            'last_login': last_login,
            'date_joined': date_joined,
            'image': request.user.image,
            'cart_skus': cart_skus,
            'count': num,
            'price_mall': num2,
            'num3': num3,
        }
        return render(request, 'user_center_site.html', context=context)

    def post(self, request):
        print("调用post方法")
        count = request.user.addresses.count()
        print(count)
        if count >= constants.USER_ADDRESS_COUNTS_LIMIT:
            return http.JsonResponse({'code': RETCODE.THROTTLINGERR, 'errmsg': '超过地址数量上限'})
        print(request.body)
        json_dict = request.body.decode("utf-8")
        json_dict = eval(json_dict)
        print("======", json_dict)
        # json_dict = json.loads(request.body.decode())
        # print(json_dict)
        username = json_dict.get("username")
        province = json_dict.get("province")
        city = json_dict.get("city")
        area = json_dict.get("area")
        addres = json_dict.get("addres")
        email = json_dict.get("email")
        mobile = json_dict.get("mobile")
        tel = json_dict.get("tel")
        print(username)
        print(province)
        parent_model = Area.objects.get(id=province)
        city = Area.objects.get(id=city)
        area = Area.objects.get(id=area)
        print(parent_model, city, area)

        Address.objects.create(
            user=request.user,
            receiver=username,
            province=parent_model,
            city=city,
            district=area,
            place=addres,
            email=email,
            mobile=mobile,
            tel=tel
        )

        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': '添加成功'})


class UpdateDestroyAddressView(LoginRequiredJSONMixin, View):
    """修改地址"""

    def get(self, request, address_id):
        """删除地址"""
        # 判断当前收货地址的id是否是属于当前用户
        address = Address.objects.get(id=address_id)
        if not (address and address.user == request.user):
            return http.HttpResponseBadRequest('非法操作')

        try:
            # 将地址逻辑删除设置为True
            address.is_deleted = True
            address.save()
        except Exception as e:
            return http.JsonResponse({'code': RETCODE.DBERR, 'errmsg': '删除地址失败'})

        return redirect(reverse('users:address'))


class UserOrderInfoView(LoginRequiredMixin, View):
    """我的订单"""

    def get(self, request, page_num):
        """提供我的订单页面"""
        last_login = request.user.last_login
        print("最近访问时间是：%s" % last_login)
        last_login = str(last_login)
        last_login = last_login.split(".")[0]
        print(last_login)
        date_joined = request.user.date_joined
        print("创建时间是：%s" % last_login)
        date_joined = str(date_joined)
        date_joined = date_joined.split(".")[0]
        print(date_joined)
        user = request.user
        # 查询订单
        orders = user.orderinfo_set.all().order_by("-create_time")
        # 遍历所有订单
        for order in orders:
            # 绑定订单状态
            order.status_name = OrderInfo.ORDER_STATUS_CHOICES[order.status - 1][1]
            # 绑定支付方式
            order.pay_method_name = OrderInfo.PAY_METHOD_CHOICES[order.pay_method - 1][1]
            order.sku_list = []
            # 查询订单商品
            order_goods = order.skus.all()
            # 遍历订单商品
            for order_good in order_goods:
                sku = order_good.sku
                sku.count = order_good.count
                sku.amount = sku.price * sku.count
                order.sku_list.append(sku)

        # 分页
        page_num = int(page_num)
        try:
            paginator = Paginator(orders, constants.ORDERS_LIST_LIMIT)
            page_orders = paginator.page(page_num)
            total_page = paginator.num_pages
        except EmptyPage:
            return http.HttpResponseNotFound('订单不存在')

        # 判断用户是否登录
        user = request.user
        print(user)
        if user.is_authenticated:
            # 用户已登录，查询Redis购物车
            redis_conn = get_redis_connection('carts')
            redis_cart = redis_conn.hgetall('carts_%s' % user.id)
            cart_selected = redis_conn.smembers('selected_%s' % user.id)
            # 将redis中的两个数据统一格式，跟cookie中的格式一致，方便统一查询
            cart_dict = {}
            for sku_id, count in redis_cart.items():
                cart_dict[int(sku_id)] = {
                    'count': int(count),
                    'selected': sku_id in cart_selected
                }
        else:
            # 用户未登录，查询cookie购物车
            cart_str = request.COOKIES.get('carts')
            if cart_str:
                cart_dict = pickle.loads(base64.b64decode(cart_str.encode()))
            else:
                cart_dict = {}

        # 构造简单购物车JSON数据
        cart_skus = []
        sku_ids = cart_dict.keys()
        skus = SKU.objects.filter(id__in=sku_ids)
        for sku in skus:
            cart_skus.append({
                'id': sku.id,
                'name': sku.name,
                'price': sku.price,
                'count': cart_dict.get(sku.id).get('count'),
                'default_image_url': sku.default_image
            })
        print(cart_skus)
        # print(len(cart_skus))
        num = 0
        num2 = 0
        num3 = list()
        for c in cart_skus:
            # print(c["count"])
            # print(c['price'])
            num1 = c['count']
            price = c['price'] * num1
            num += num1
            num3.append(num1)
            num2 += price
        # print(num)
        # print(num2)
        print(num3)
        context = {
            "page_orders": page_orders,
            'total_page': total_page,
            'page_num': page_num,
            'last_login': last_login,
            'date_joined': date_joined,
            'image': request.user.image,
            'cart_skus': cart_skus,
            'count': num,
            'price_mall': num2,
            'num3': num3,
        }
        return render(request, "user_center_order.html", context)